import { config } from '../config/env.js'
import { APIError } from '../middleware/error.js'

export interface RetryOptions {
  maxAttempts?: number
  initialDelay?: number
  maxDelay?: number
  shouldRetry?: (error: unknown) => boolean
}

/**
 * Retry a function with exponential backoff
 */
export async function retryWithBackoff<T>(
  fn: () => Promise<T>,
  options: RetryOptions = {}
): Promise<T> {
  const {
    maxAttempts = config.api.retryAttempts,
    initialDelay = 1000,
    maxDelay = 10000,
    shouldRetry = defaultShouldRetry,
  } = options

  let lastError: unknown
  
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    try {
      return await fn()
    } catch (error) {
      lastError = error
      
      // Don't retry if it's not a retryable error
      if (!shouldRetry(error)) {
        throw error
      }
      
      // Don't retry on last attempt
      if (attempt === maxAttempts - 1) {
        throw error
      }
      
      // Calculate exponential backoff delay
      const delay = Math.min(initialDelay * Math.pow(2, attempt), maxDelay)
      
      // Wait before retrying
      await sleep(delay)
    }
  }
  
  throw lastError
}

function defaultShouldRetry(error: unknown): boolean {
  if (error instanceof APIError) {
    // Retry on rate limit errors and other retryable errors
    return error.retryable
  }
  
  // Retry on network errors
  if (error instanceof Error) {
    return error.name === 'TimeoutError' || error.message.includes('fetch')
  }
  
  return false
}

function sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms))
}
